Skip to content

fix: Copy mutable collections before passing to scope observers#7807

Merged
antonis merged 4 commits intomainfrom
fix/scope-observer-race-condition
Apr 16, 2026
Merged

fix: Copy mutable collections before passing to scope observers#7807
antonis merged 4 commits intomainfrom
fix/scope-observer-race-condition

Conversation

@antonis
Copy link
Copy Markdown
Contributor

@antonis antonis commented Apr 16, 2026

📜 Description

Copy mutable collections (_contextDictionary, _tagDictionary, _extraDictionary, _fingerprintArray, _attributesDictionary) before passing them to scope observers in SentryScope.m. This prevents a race condition where observers dispatch async work that iterates the collection after the @synchronized lock is released, while another thread mutates it concurrently.

Also updates the misleading thread-safety comment in SentryWatchdogTerminationScopeObserver.swift to accurately describe the guarantee.

💡 Motivation and Context

Fixes a launch crash (EXC_BAD_ACCESS in objc_msgSend) reported in getsentry/sentry-react-native#5995 affecting <1% of cold launches on iOS 26+. The crash occurs because SentryWatchdogTerminationScopeObserver captures mutable collection references and dispatches async disk writes, racing with concurrent scope mutations.

The public getter methods (context, extras, tags, fingerprints, attributes) already return .copy — this fix makes observer notifications consistent with that pattern.

💚 How did you test it?

  • Added testModifyingFromMultipleThreads_withObserverAsyncDispatch — a concurrent stress test that rapidly mutates scope context/tags/extras/fingerprint from multiple threads while an observer with async dispatch is active
  • All existing SentryScopeSwiftTests (59 tests) pass
  • All existing SentryWatchdogTerminationScopeObserverTests (18 tests) pass
  • make format, make analyze, make build-ios all clean

📝 Checklist

You have to check all boxes before merging:

  • I added tests to verify the changes.
  • No new PII added or SDK only sends newly added PII if sendDefaultPII is enabled.
  • I updated the docs if needed.
  • I updated the wizard if needed.
  • Review from the native team if needed.
  • No breaking change or entry added to the changelog.
  • No breaking change for hybrid SDKs or communicated to hybrid SDKs.

SentryScope passes mutable collections to scope observers inside
@synchronized blocks. Observers like WatchdogTermination dispatch
async work that iterates the collection after the lock is released,
racing with concurrent mutations — causing EXC_BAD_ACCESS.

Copy collections before passing to observers, consistent with
the existing public getter methods that already return copies.
@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Apr 16, 2026

Semver Impact of This PR

🟢 Patch (bug fixes)

📋 Changelog Preview

This is how your changes will appear in the changelog.
Entries from this PR are highlighted with a left border (blockquote style).


Bug Fixes 🐛

  • (replay) Keep replayType as buffer for Session Replay triggered by an error by romtsn in #7804
  • Copy mutable collections before passing to scope observers by antonis in #7807
  • Detect development builds via provisioning profile entitlement by denrase in #7702

Internal Changes 🔧

Deps

  • Bump actions/upload-pages-artifact from 4.0.0 to 5.0.0 by dependabot in #7789
  • Bump actions/github-script from 8.0.0 to 9.0.0 by dependabot in #7793

🤖 This preview updates automatically when you update the PR.

@antonis
Copy link
Copy Markdown
Contributor Author

antonis commented Apr 16, 2026

@cursor review

@antonis
Copy link
Copy Markdown
Contributor Author

antonis commented Apr 16, 2026

@sentry review

Copy link
Copy Markdown

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Bugbot reviewed your changes and found no new issues!

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit dd9ad6b. Configure here.

@codecov
Copy link
Copy Markdown

codecov bot commented Apr 16, 2026

Codecov Report

❌ Patch coverage is 90.90909% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 85.408%. Comparing base (1723b14) to head (59d8fd0).
⚠️ Report is 1 commits behind head on main.
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
Sources/Sentry/SentryScope.m 90.909% 1 Missing ⚠️
Additional details and impacted files

Impacted file tree graph

@@              Coverage Diff              @@
##              main     #7807       +/-   ##
=============================================
- Coverage   85.418%   85.408%   -0.011%     
=============================================
  Files          487       487               
  Lines        29195     29195               
  Branches     12632     12634        +2     
=============================================
- Hits         24938     24935        -3     
- Misses        4207      4209        +2     
- Partials        50        51        +1     
Files with missing lines Coverage Δ
...tions/SentryWatchdogTerminationScopeObserver.swift 75.000% <ø> (ø)
Sources/Sentry/SentryScope.m 96.884% <90.909%> (+0.623%) ⬆️

... and 4 files with indirect coverage changes


Continue to review full report in Codecov by Sentry.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 1723b14...59d8fd0. Read the comment docs.

@antonis antonis marked this pull request as ready for review April 16, 2026 09:08
Copy link
Copy Markdown
Member

@philprime philprime left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approving this already, but please take a look at my comments and decide what makes more sense.

Comment thread Sources/Sentry/SentryScope.m Outdated
Comment thread Tests/SentryTests/SentryScopeSwiftTests.swift
@philprime philprime added the ready-to-merge Use this label to trigger all PR workflows label Apr 16, 2026
@sentry
Copy link
Copy Markdown

sentry bot commented Apr 16, 2026

📲 Install Builds

iOS

🔗 App Name App ID Version Configuration
SDK-Size io.sentry.sample.SDK-Size 9.10.0 (1) Release

⚙️ sentry-cocoa Build Distribution Settings

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Apr 16, 2026

Performance metrics 🚀

  Plain With Sentry Diff
Startup time 1224.42 ms 1260.09 ms 35.67 ms
Size 24.14 KiB 1.13 MiB 1.11 MiB

Baseline results on branch: main

Startup times

Revision Plain With Sentry Diff
3461f50 1228.08 ms 1263.37 ms 35.29 ms
5b1e2a1 1217.63 ms 1245.49 ms 27.86 ms
e1e5f3b 1220.60 ms 1241.63 ms 21.04 ms
fe6228d 1215.81 ms 1234.04 ms 18.23 ms
93ef486 1220.22 ms 1244.96 ms 24.74 ms
e06cf5f 1222.96 ms 1254.66 ms 31.70 ms
14bb180 1222.75 ms 1252.47 ms 29.72 ms
387fbe4 1226.19 ms 1251.98 ms 25.79 ms
b2f3bdd 1219.09 ms 1256.42 ms 37.33 ms
a1a9260 1192.15 ms 1229.80 ms 37.64 ms

App size

Revision Plain With Sentry Diff
3461f50 24.14 KiB 1.11 MiB 1.09 MiB
5b1e2a1 24.14 KiB 1.11 MiB 1.09 MiB
e1e5f3b 24.14 KiB 1.06 MiB 1.04 MiB
fe6228d 24.14 KiB 1.11 MiB 1.08 MiB
93ef486 24.14 KiB 1.06 MiB 1.04 MiB
e06cf5f 24.14 KiB 1.13 MiB 1.10 MiB
14bb180 24.14 KiB 1.12 MiB 1.10 MiB
387fbe4 24.14 KiB 1.07 MiB 1.04 MiB
b2f3bdd 24.14 KiB 1.11 MiB 1.08 MiB
a1a9260 24.14 KiB 1.08 MiB 1.06 MiB

Previous results on branch: fix/scope-observer-race-condition

Startup times

Revision Plain With Sentry Diff
fdbda99 1226.95 ms 1253.04 ms 26.09 ms

App size

Revision Plain With Sentry Diff
fdbda99 24.14 KiB 1.13 MiB 1.11 MiB

Comment thread Sources/Sentry/SentryScope.m
Copy link
Copy Markdown

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 59d8fd0. Configure here.

Comment thread Sources/Sentry/SentryScope.m
@antonis antonis merged commit 1b7b7b4 into main Apr 16, 2026
208 checks passed
@antonis antonis deleted the fix/scope-observer-race-condition branch April 16, 2026 13:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ready-to-merge Use this label to trigger all PR workflows

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Launch crash in SentryWatchdogTerminationAttributesProcessor after upgrading to 8.5.0 with native init

2 participants